package com.zj.controller;

import com.zj.pojo.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.*;

@RestControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(value = Exception.class)
    public Result handleException(Exception e, HttpServletRequest request) {
        // 记录日志
        logFromExceptionAndReq(e,request);

        String message =canExposeError(request) ? printStackTraceToString(e) :
                HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
        // 返回自定义错误信息
        return new Result<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), message, null);
//        return new ResponseEntity<>("全局异常处理: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }

    private boolean canExposeError(HttpServletRequest request){
        String exposeError = request.getHeader("ExposeError");
        //可加入权限校验，只有管理员可用
        return StringUtils.hasLength(exposeError) && "true".equals(exposeError);
    }

    private void logFromExceptionAndReq(Exception e, HttpServletRequest request){
//        // 1. 获取 Controller 方法信息（类名、方法名、参数类型）
//        HandlerMethod handlerMethod = getHandlerMethod(request);
//        String controllerName = "";
//        String methodName = "";
//        List<String> methodParamNames = new ArrayList<>();
//        if (handlerMethod != null) {
//            // Controller 类名（含包名，可通过 getSimpleName() 只取类名）
//            controllerName = handlerMethod.getBeanType().getName();
//            // Controller 方法名
//            methodName = handlerMethod.getMethod().getName();
//            // Controller 方法的参数名（如：[id, user]）
//            for (MethodParameter param : handlerMethod.getMethodParameters()) {
//                methodParamNames.add(param.getParameterName());
//            }
//        }

        // 2. 获取请求参数（路径参数、请求体、请求头、请求参数）
        Map<String, Object> requestParams = new HashMap<>();
        requestParams.put("requestURI",request.getRequestURL());
        // 2.1 路径参数（如 /user/{id} 中的 id）
        Map<String, String> pathParams = (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
        requestParams.put("pathParams", pathParams != null ? pathParams : Collections.emptyMap());

        // 2.2 请求参数（Query 参数，如 /user?name=张三）
        Map<String, String[]> queryParams = request.getParameterMap();
        Map<String, String> queryParamsSimplified = new HashMap<>();
        queryParams.forEach((key, values) -> queryParamsSimplified.put(key, Arrays.toString(values)));
        requestParams.put("queryParams", queryParamsSimplified);

        // 2.3 请求头（如 token、Content-Type）
        Map<String, String> headers = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            headers.put(headerName, request.getHeader(headerName));
        }
        requestParams.put("headers", headers);

        // 2.4 请求体（JSON/表单数据，需通过 ContentCachingRequestWrapper 缓存）
        String requestBody = getRequestBody(request);
        requestParams.put("requestBody", requestBody != null ? requestBody : "");

        // 3. 日志打印（生产环境建议用 logback/log4j 记录）
        logger.error(
//                "捕获异常：{},\nController 类：{},\n方法：{},\n方法参数名：{},\n
                "请求参数：{}",
//                e.getMessage(),
//                controllerName,
//                methodName,
//                methodParamNames,
                requestParams

        );
        logger.error("异常栈信息：{}",e);
    }

    /**
     * 从请求中获取 HandlerMethod（Controller 方法对象）
     */
    private HandlerMethod getHandlerMethod(HttpServletRequest request) {
        try {
            // 从请求属性中获取 HandlerMethod（Spring 自动存入）
            Object handler = request.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE);
            if (handler instanceof HandlerMethod) {
                return (HandlerMethod) handler;
            }
        } catch (Exception ignored) {
            // 若未找到（如非 Controller 请求触发的异常），返回 null
        }
        return null;
    }

    /**
     * 获取请求体（解决 request.getInputStream() 只能读取一次的问题）
     */
    private String getRequestBody(HttpServletRequest request) {
        try {
            // 若 request 是 ContentCachingRequestWrapper 类型（已缓存请求体），直接读取
            if (request instanceof ContentCachingRequestWrapper) {
                ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) request;
                byte[] content = wrapper.getContentAsByteArray();
                if (content.length > 0) {
                    // 根据请求头的 Content-Type 选择字符集（默认 UTF-8）
                    String charset = request.getCharacterEncoding() != null ? request.getCharacterEncoding() : "UTF-8";
                    return new String(content, charset);
                }
            }
            // 若不是，说明请求体未被缓存（如 GET 请求无请求体），返回 null
        } catch (Exception ignored) {
        }
        return null;
    }

    public static String printStackTraceToString(Throwable t) {
        StringWriter sw = new StringWriter();
        t.printStackTrace(new PrintWriter(sw, true));
        return sw.getBuffer().toString();
    }

    public static void main(String[] args) {
        ArrayList list = new ArrayList<String>();
        list.add("AA");
        list.add("bb");
        list.add("dd");
        System.out.println(list);//自定义扩展类的异常应该放在DefaultHandlerExceptionResolver前面
        list.add(list.size()-1,"cc");
        System.out.println(list);
    }

}
